﻿#include "qwristwatchwidget.h"

#include <QDateTime>
#include <QPainter>
#include <QDebug>
#include <QMouseEvent>
#include <QtMath>

const QStringList s_directions = QStringList() << "北" << "东" << "南" << "西";
QWristWatchWidget::QWristWatchWidget(QWidget *parent) : QWidget(parent),
    m_angle(0),m_scale(1.0)
{
    this->setAttribute(Qt::WA_TranslucentBackground);
    this->setMouseTracking(true);
    if (parent == 0) { this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint); }

    m_timer = new QTimer(this);
    m_timer->setInterval(1000);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(sltTimeout()));

    m_strText = getDirection();

    m_animation = new QPropertyAnimation(this, "angle");
    m_animation->setEasingCurve(QEasingCurve::OutBounce);
    m_animation->setDuration(1000);


    m_isPressed = false;
    m_isMoved = false;
    setWatchType(StopWatch);
    clearStopwatch();
}

QWristWatchWidget::~QWristWatchWidget()
{
    if (m_animation->state() != QPropertyAnimation::Stopped) m_animation->stop();
    delete m_animation;
    m_animation = Q_NULLPTR;

    if (m_timer->isActive()) m_timer->stop();
}

qreal QWristWatchWidget::angle() const
{
    return m_angle;
}

void QWristWatchWidget::setAngle(const qreal &angle)
{
    m_angle = angle;
    this->update();
}

void QWristWatchWidget::setWatchType(int type)
{
    m_clockType = (WatchType)type;
    if (Clock == type) {
        m_timer->setInterval(1000);
    } else if (StopWatch == m_clockType) {
        m_timer->setInterval(10);
    }
    this->update();
}

void QWristWatchWidget::sltTimeout()
{
    if (Clock == m_clockType) {
    } else if (StopWatch == m_clockType) {
        m_msecond ++;
        if (m_msecond > 99) {
            m_msecond = 0;
            m_second ++;
        }

        if (m_second > 59) {
            m_second = 0;
            m_minute ++;
        }

        if (m_minute > 59) {
            m_minute = 0;
            m_hour++;
        }
    }

    this->update(m_updateRect);
}

QString QWristWatchWidget::getDirection(qreal _angle)
{
    QString strDir = "正北";
    qreal offset = 0;
    if (0 < _angle && _angle < 90) {
        strDir = "东北";
        offset = _angle;
    } else if (90 < _angle && _angle < 180) {
        strDir = "东南";
        offset = _angle - 90;
    } else if (180 < _angle && _angle < 270) {
        strDir = "西南";
        offset = _angle - 180;
    } else if (270 < _angle && _angle < 360) {
        strDir = "西北";
        offset = _angle - 270;
    }

    return QString("%1°").arg(offset) + strDir;
}

void QWristWatchWidget::clearStopwatch()
{
    m_hour = 0;
    m_minute = 0;
    m_second = 0;
    m_msecond = 0;
    this->update();
}

bool QWristWatchWidget::isClearStopwatch()
{
    return (!m_timer->isActive() && (m_hour != 0 || m_minute != 0 || m_second != 0 || m_msecond != 0));
}

void QWristWatchWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.drawPixmap(0, 0, QPixmap(":/images/watch_bg.png"));

    painter.translate(this->width() / 2, this->height()  / 2);
    painter.scale(m_scale, m_scale);

    painter.setPen(QPen(QColor("#656577"), 2, Qt::SolidLine));
    painter.setBrush(QColor("#000000"));
    int radius = 98;
    painter.drawEllipse(-radius, -radius, radius * 2, radius * 2);

    QFont font("Microsoft YaHei");
    font.setPixelSize(14);
    painter.setFont(font);

    if (Clock == m_clockType) {
        drawClockScale(&painter);
        drawClockHandle(&painter);
    } else if (StopWatch == m_clockType) {
        drawStopwatchScale(&painter);
        drawStopwatchHandle(&painter);
    } else if (Compass == m_clockType) {
        drawCompassClockDial(&painter);
        drawCompassHandle(&painter);
    }
}

void QWristWatchWidget::drawClockScale(QPainter *painter)
{
    painter->save();
    int nH = 4;
    bool isMax = false;
    int radius = 90;

    painter->save();
    for (int i = 0; i < 60; i++) {
        isMax = (0 == (i % 5));
        nH = isMax ? 6 : 4;
        painter->setPen(isMax ? QColor("#ffffff") : QColor("#666666"));
        painter->drawLine(QPoint(0, -radius), QPoint(0, -radius + nH));
        painter->rotate(6);
    }
    painter->restore();

#if 1
    // 正向刻度标识
    painter->setPen(Qt::white);
    QFont font("SimSun");
    font.setPixelSize(12);
    font.setBold(true);
    painter->setFont(font);
    nH = painter->fontMetrics().height();
    radius -= 14;
    painter->setPen(QColor("#ffffff"));
    for (int i = 1; i <= 12; i++)
    {
        QString strTxt = QString("%1").arg(i);
        int nW = painter->fontMetrics().horizontalAdvance(strTxt);
        painter->drawText(QRect(radius * cos(M_PI * (i - 1) / 6 - M_PI / 3) - nW / 2,
                                radius * sin(M_PI * (i - 1) / 6 - M_PI / 3) - nH / 2,
                                nW, nH), Qt::AlignCenter, strTxt);
    }
#endif

    radius = 96;
    painter->setPen(QPen(QColor("#868793"), 2, Qt::SolidLine));
    painter->setBrush(Qt::NoBrush);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);

#if 1
    painter->setPen(QColor("#ffffff"));
    painter->drawText(QRect(-radius, 20, radius * 2, 40), Qt::AlignCenter, QTime::currentTime().toString("hh:mm:ss"));
#endif
    painter->restore();
}

void QWristWatchWidget::drawClockHandle(QPainter *painter)
{
    const static QPoint sec[4] = { QPoint(0, -90), QPoint(2, 0), QPoint(0, 20), QPoint(-2, 0) };
    const static QPoint min[4] = { QPoint(0, -62), QPoint(4, 0), QPoint(0, 10), QPoint(-4, 0) };
    const static QPoint hour[4] = { QPoint(0, -48), QPoint(5, 0), QPoint(0, 11), QPoint(-5, 0) };
    painter->save();
    QTime time = QTime::currentTime();

    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor("#dad9df"));
    painter->rotate(30.0 * time.hour() + (time.minute() * 1.0) / 2.0);
    painter->drawPolygon(hour, 4);
    painter->restore();

    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor("#d66680"));
    painter->rotate(6.0 * time.minute() + (time.second() * 1.0) / 10.0);
    painter->drawPolygon(min, 4);
    painter->restore();

    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor("#3561de"));
    painter->rotate(6.0 * time.second());
    painter->drawPolygon(sec, 4);
    painter->restore();

#if 1
    painter->setPen(QColor("#ffffff"));
    painter->setBrush(QColor("#aaaaaa"));
    painter->drawEllipse(-5, -5, 10, 10);
#endif

    painter->restore();
}

void QWristWatchWidget::drawStopwatchScale(QPainter *painter)
{
    painter->save();
    int radius = 90;
    painter->rotate(-135);
    painter->setPen(QColor("#666666"));
    for (int i = 0; i < 135; i++) {
        painter->drawLine(QPoint(0, -radius), QPoint(0, -radius + 4));
        painter->rotate(2);
    }
    painter->restore();

    painter->save();
    painter->rotate(-75);
    radius = 55;
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor("#95959d"));
    for (int i = 0; i < 9; i++) {
        painter->drawEllipse(-radius, -radius, 4, 4);
        painter->rotate(30);
    }
    painter->restore();

    radius = 94;
    painter->setPen(QColor("#666666"));
    painter->drawArc(QRectF(-radius, -radius, radius * 2, radius * 2), 150 * 16, 60 * 16);
    painter->drawArc(QRectF(-radius, -radius, radius * 2, radius * 2), 30 * 16, -60 * 16);
}

void QWristWatchWidget::drawStopwatchHandle(QPainter *painter)
{
    painter->save();
    QFont font("Bahnschrift Light");
    font.setPixelSize(24);
    font.setBold(true);
    font.setLetterSpacing(QFont::AbsoluteSpacing, 0);
    painter->setFont(font);

    painter->setPen(QColor("#ffffff"));
    //    qDebug() << painter->fontMetrics().horizontalAdvance("0") << painter->fontMetrics().horizontalAdvance(":");
    QRect rect(-65, -40, 28, 40);
    painter->drawText(rect, Qt::AlignCenter, QString("%1").arg(m_hour, 2, 10, QChar('0')));

    rect = QRect(rect.right(), rect.top(), 6, rect.height());
    painter->drawText(rect, Qt::AlignCenter, QString(":"));

    rect = QRect(rect.right(), rect.top(), 28, rect.height());
    painter->drawText(rect, Qt::AlignCenter, QString("%1").arg(m_minute, 2, 10, QChar('0')));

    rect = QRect(rect.right(), rect.top(), 6, rect.height());
    painter->drawText(rect, Qt::AlignCenter, QString(":"));

    rect = QRect(rect.right(), rect.top(), 28, rect.height());
    painter->drawText(rect, Qt::AlignCenter, QString("%1").arg(m_second, 2, 10, QChar('0')));

    rect = QRect(rect.right(), rect.top(), 6, rect.height());
    painter->drawText(rect, Qt::AlignCenter, QString(":"));

    rect = QRect(rect.right(), rect.top(), 28, rect.height());
    painter->drawText(rect, Qt::AlignCenter, QString("%1").arg(m_msecond, 2, 10, QChar('0')));

    painter->setPen(Qt::NoPen);
    painter->setBrush(isClearStopwatch() ? QColor("#ef013b") : QColor("#252527"));
    painter->drawEllipse(-55, 15, 40, 40);
    painter->setBrush(m_timer->isActive() ? QColor("#ef013b") : QColor("#2d6ffd"));
    painter->drawEllipse(15, 15, 40, 40);

    font.setFamily("Microsoft YaHei");
    font.setPixelSize(12);
    painter->setFont(font);
    painter->setPen(QColor("#ffffff"));
    painter->drawText(QRect(-55, 15, 40, 40), Qt::AlignCenter, isClearStopwatch() ? QString("停止") : QString("计次"));
    painter->drawText(QRect(15, 15, 40, 40), Qt::AlignCenter, m_timer->isActive() ? QString("暂停") : QString("开始"));
    painter->restore();
}

void QWristWatchWidget::drawCompassClockDial(QPainter *painter)
{
    painter->save();

    QFont font = painter->font();
    font.setPixelSize(14);
    painter->setFont(font);

    int nW = painter->fontMetrics().horizontalAdvance("东");
    int nH = 4;
    bool isMax = false;
    painter->rotate(-m_angle);
    int radius = 90;
    for (int i = 0; i < 180; i++) {
        isMax = (0 == (i % 15));
        nH = isMax ? 6 : 4;
        painter->setPen(isMax ? QColor("#ffffff") : QColor("#666666"));
        painter->drawLine(QPoint(0, -radius), QPoint(0, -radius + nH));
        if (0 == i % 45) {
            int index = i / 45;
            if (0 == index) painter->setPen(QColor("#ee013a"));
            else if (2 == index) painter->setPen(QColor("#2d6ffd"));
            else painter->setPen(QColor("#ffffff"));
            font.setPixelSize(14);
            painter->setFont(font);
            nW = painter->fontMetrics().horizontalAdvance("东");
            painter->drawText(QRect(-nW / 2, -radius + nH, nW, painter->fontMetrics().height()), s_directions.at(index));
        } else if (isMax) {
            font.setPixelSize(8);
            painter->setFont(font);
            nW = painter->fontMetrics().horizontalAdvance(QString::number(i * 2));
            painter->setPen(QColor("#666666"));
            painter->drawText(QRect(-nW / 2, -radius + nH, nW, painter->fontMetrics().height()), QString::number(i * 2));
        }
        painter->rotate(2);
    }

    radius = 96;
    painter->setPen(QPen(QColor("#868793"), 2, Qt::SolidLine));
    painter->setBrush(Qt::NoBrush);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);

    painter->restore();
}

void QWristWatchWidget::drawCompassHandle(QPainter *painter)
{
    int radius = 45;
    painter->save();
    painter->setPen(QPen(QColor("#272727"), 2, Qt::SolidLine));

    painter->save();
    for (int i = 1; i < 24; i++) {
        painter->rotate(15);
        if (0 == i % 6) painter->drawLine(QPoint(0, -radius - 5), QPoint(0, -radius + 5));
        else painter->drawPoint(0, -radius);
    }
    painter->restore();

    static const QPointF s_points[3] = {
        QPointF(0, -50.0),
        QPointF(-5, -40),
        QPointF(5, -40),
    };
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor("#ef013b"));
    painter->drawPolygon(s_points, 3);

    radius -= 5;
    painter->setPen(QPen(QColor("#272727"), 2, Qt::SolidLine));
    painter->setBrush(Qt::NoBrush);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);

    radius -= 5;
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor("#272727"));
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);

    painter->setPen(QColor("#ffffff"));
    QFont font = painter->font();
    font.setPixelSize(14);
    painter->setFont(font);
    painter->drawText(QRect(-radius, -radius, radius * 2, radius * 2), Qt::AlignCenter, m_strText);

    painter->restore();
}

void QWristWatchWidget::mousePressEvent(QMouseEvent *e)
{
    if (Qt::LeftButton == e->button()) {
        m_isPressed = true;
        m_isMoved = false;
        m_startPos = e->pos();
    } else if (Compass == m_clockType) {
        if (m_animation->state() != QPropertyAnimation::Stopped) m_animation->stop();
        m_animation->setStartValue(m_angle);
        int offset = m_angle + qrand() % 360;
        offset = (offset) % 360;
        m_animation->setEndValue(offset);
        m_animation->start();
        m_strText = getDirection(offset);
    } else if (Clock == m_clockType) {

    }
}

void QWristWatchWidget::mouseMoveEvent(QMouseEvent *e)
{
    if (m_isPressed && this->parent() == 0) {
        m_isMoved = true;
        this->move(e->globalPos() - m_startPos);
    }

    this->setCursor((m_startRect.contains(e->pos()) || m_recordRect.contains(e->pos())) ? Qt::PointingHandCursor : Qt::ArrowCursor);

}

void QWristWatchWidget::mouseReleaseEvent(QMouseEvent *e)
{
    m_isPressed = false;
    if (StopWatch == m_clockType && Qt::LeftButton == e->button() && !m_isMoved) {
        if (m_recordRect.contains(e->pos())) {
            if (m_timer->isActive()) m_timer->stop();
            else m_timer->start();
            this->update(m_recordRect);
            this->update(m_startRect);
        }

        if (m_startRect.contains(e->pos())) {
            if (isClearStopwatch()) clearStopwatch();
            else {
                QString strTxt = QString("%1:%2:%3:%4").arg(m_hour, 2, 10, QChar('0'))
                        .arg(m_minute, 2, 10, QChar('0'))
                        .arg(m_second, 2, 10, QChar('0'))
                        .arg(m_msecond, 2, 10, QChar('0'));
                m_stopWatchRcd.append(strTxt);
            }
        }
    }
    QWidget::mouseReleaseEvent(e);
}

void QWristWatchWidget::mouseDoubleClickEvent(QMouseEvent *e)
{
    if (e->button() == Qt::LeftButton && this->parent() == 0) {
        this->close();
    }
}

QSize QWristWatchWidget::sizeHint() const
{
    return  QSize(310, 476);
}

void QWristWatchWidget::hideEvent(QHideEvent *event)
{
    if (m_timer->isActive()) m_timer->stop();
    QWidget::hideEvent(event);
}

void QWristWatchWidget::showEvent(QShowEvent *event)
{
    if (Clock == m_clockType && !m_timer->isActive()) {
        m_timer->start();
    }

    QWidget::showEvent(event);
}

void QWristWatchWidget::resizeEvent(QResizeEvent *event)
{
    int side = qMin(this->width(), this->height());
    m_scale = side * 1.0 / 200;
    int x = this->width() / 2;
    int y = this->height() / 2;
    m_recordRect = QRect(0, 0, 0, 0);
    m_startRect = QRect(0, 0, 0, 0);

    if (StopWatch == m_clockType) {
        m_updateRect = QRect(x - 65 * m_scale, y - 40 * m_scale,  130 * m_scale, 40 * m_scale);
        m_recordRect = QRect(x + 15 * m_scale, y + 15 * m_scale, 40 * m_scale, 40 * m_scale);
        m_startRect = QRect(x - 55 * m_scale, y + 15 * m_scale, 40 * m_scale, 40 * m_scale);
    } else m_updateRect = this->rect();

    QWidget::resizeEvent(event);
}
